Einführung

  • Bisher haben wir ausschließlich statische Grafiken erzeugt.
  • Forschungsergebnisse werden zunehmend nicht mehr nur in Printmedien dargestellt, sodass wir animierte und interaktive Grafiken teilen können. So kann noch mehr Information in einer einzigen “Grafik” zugänglich gemacht werden!

Foto von Jakob Owens auf Unsplash

Vorbereitung

Pakete, die wir für die Beispiele im Foliensatz benötigen:

library(ggplot2)
library(dplyr)
library(tidyr)
library(ggthemes)
library(gganimate)
library(plotly)
library(htmlwidgets)

Datensatz

gapminder <- readRDS(here::here("data", "gapminder_dat.rds"))

Animierte Grafiken

  • Die Grundidee bei animierten Grafiken ist es, nicht einen einzigen Plot zu erstellen, sondern stattdessen sehr viele Einzelgrafiken, die dann als einzelne Bilder zu einem Film zusammengefügt werden. Das übernimmt gganimate für uns!
  • Zwei zentrale Fragen, die man sich stellen sollte, bevor man anfängt Daten zu animieren:
    - “Gewinnt der Betrachter bzw. die Betrachterin dabei zusätzliche Information?”
    - “Ist es den Aufwand wert?”

Dokumentation bzw. weiterführende Quellen:

Animierte Grafiken

Ausgangspunkt für eine animierte Grafik mit gganimate ist eine statische, mit ggplot2 erzeugte Grafik.

gapminder_line_g7 <- gapminder %>%
  filter(country %in% c("can", "fra", "deu", "ita", "jpn", "gbr", "usa"), time >=1900, time <= 2024) %>%
  drop_na(gini)

labels_g7 <- c(
  "can" = "Kanada",
  "fra" = "Frankreich",
  "deu" = "Deutschland",
  "ita" = "Italien",
  "jpn" = "Japan",
  "gbr" = "Vereinigtes Königreich",
  "usa" = "USA"
)

gapminder_line_g7$country_de <- labels_g7[gapminder_line_g7$country]
gapminder_line_g7$country_de <- factor(gapminder_line_g7$country_de,
                        levels = sort(unique(gapminder_line_g7$country_de)))

p_line_g7 <- ggplot(data = gapminder_line_g7, aes(x = time, y = gini)) +
  geom_line(aes(col = country_de)) +  
  labs(title = "Ungleichheit On the Rise", 
     subtitle = "Gini-Koeffizient in den G7-Staaten von 1900 bis 2024",
     x = "Jahr",
     y = "Gini-Koeffizient", 
     col = "G7-Staat") +
  scale_color_discrete(labels = labels_g7) +
  theme_solarized() 

p_line_g7

Animierte Grafiken

Mit transition_reveal(along = time) werden die Linien über die Zeit “enthüllt”.

p_line_g7 + 
  transition_reveal(along = time) +# Linien werden über die Zeit "enthüllt"
  ease_aes("linear")  

Noch mehr animierte Grafiken

Auch unser bubble chart lässt sich animieren. Dies ist die statische Ausgangsbasis.

options(scipen=10)

# Farben der vier Weltregionen 
tuerkis <- rgb(0,213,233, max=255)
gruen <- rgb(127,235,0, max=255)
rot <- rgb(255,88,114, max=255)
gelb <- rgb(255,231,0, max=255)

p_static <- gapminder %>%
  # Auswahl der Daten von 2019:
  subset(time == 2019) %>% 
    # Neu: Angabe der Einwohnerzahl in Millionen
  mutate(pop = pop/1000000) %>%
  # Grund-Grafik anfordern:
  ggplot(aes(x=gini, y=hapiscore_whr)) +
  # Neu: Text für die Jahreszahl einfügen, sodass diese ganz im Hintergrund steht
  annotate("text", x=45, y=50, label="2019", size=85, colour ="grey90", family="mono", fontface=1) +
  # Neu: Farbthema: heller Hintergrund, schwarze Linien an x- und y-Achse
  theme_classic() + 
  # Wie bisher: Punkte einzeichnen --> Streu-Punkt-Diagramm,
  # Neu: Unterscheidung der Punkte nach Farbe (Region) und Größe (Population);  
  # Transparenz der Datenpunkte (alpha), Rand um die Punkte (shape) 
  geom_point(aes(fill = world_4region, size = pop), shape=21, alpha=.7) +
  # Skalieren der Größe der Punkte, sodass die Unterschiede deutlicher sind
  scale_size(range = c(1, 30)) +
  # Neu: Beschriftung der Achsen
  labs(x="Gini-Index", y="Hyppiness Score") +
  # Neu: manuelle Spezifikation der y-Achse: Wertebereich, Position der Beschriftungen (10er-Schritte)
  scale_y_continuous(limits = c(15, 85), 
                     breaks = seq(20,80, by=10),
                     labels = paste0(seq(20,80, by=10), "%")) +
  # Neu: manuelle Spezifikation der x-Achse: Wertebereich, log-Transformation, Position und Name der Beschriftungen
  scale_x_continuous(limits = c(18,75),
                     breaks = seq(20,70, by= 5)) +
  # Neu: manuelle Spezifikation der Farben
  scale_fill_manual(
    values = c(tuerkis, gruen, rot, gelb),
    breaks = c("africa", "americas", "asia", "europe")) +
  # Neu: Theme (Anpassung der Schriftgroesse, relativ zur Groesse 12, blaues Raster im Hintergrund, Rand für die Legende)
  theme(text = element_text(size=12),
        axis.text = element_text(size=rel(.8)),
        axis.title = element_text(size=rel(1.2)),
        panel.grid.major = element_line(colour = "azure2")) +
  # Neu: Titel, Beschriftungen der Achse und Legende
  labs(title="Bubble Chart im Gapminder-Look",
       subtitle="Jahr: 2023",
       x="Gini-Index",
       y="Happiness Score (WHR)",
       fill="Weltregion",
       size="Einwohnerzahl\n(in Mio.)") +
  # Neu: Vergroessern der Punkte fuer die Farb-Legende fuer die Kontinente
  guides(fill = guide_legend(override.aes = list(size = 5), order=1))  

p_static

Noch mehr animierte Grafiken

Nun wird für jedes Jahr ein neues Bubble chart erzeugt.

options(scipen=10)

# Farben der vier Weltregionen 
tuerkis <- rgb(0,213,233, max=255)
gruen <- rgb(127,235,0, max=255)
rot <- rgb(255,88,114, max=255)
gelb <- rgb(255,231,0, max=255)

p_static <- gapminder %>%
  subset(time >= 2005 & time <= 2023) %>% 
  # Neu: Angabe der Einwohnerzahl in Millionen
  mutate(pop = pop/1000000) %>%
  # Grund-Grafik anfordern:
  ggplot(aes(x=gini, y=hapiscore_whr)) +
  # Neu: Text für die Jahreszahl einfügen, sodass diese ganz im Hintergrund steht
  # ...funktioniert nicht ohne weiteres...
  # Neu: Farbthema: heller Hintergrund, schwarze Linien an x- und y-Achse
  theme_classic() + 
  # Wie bisher: Punkte einzeichnen --> Streu-Punkt-Diagramm,
  # Neu: Unterscheidung der Punkte nach Farbe (Region) und Größe (Population);  
  # Transparenz der Datenpunkte (alpha), Rand um die Punkte (shape) 
  geom_point(aes(fill = world_4region, size = pop), shape=21, alpha=.7) +
  # Skalieren der Größe der Punkte, sodass die Unterschiede deutlicher sind
  scale_size(range = c(1, 30)) +
  # Neu: Beschriftung der Achsen
  labs(x="Gini-Index", y="Hyppiness Score") +
  # Neu: manuelle Spezifikation der y-Achse: Wertebereich, Position der Beschriftungen (10er-Schritte)
  scale_y_continuous(limits = c(15, 85), 
                     breaks = seq(20,80, by=10),
                     labels = paste0(seq(20,80, by=10), "%")) +
  # Neu: manuelle Spezifikation der x-Achse: Wertebereich, log-Transformation, Position und Name der Beschriftungen
  scale_x_continuous(limits = c(18,75),
                     breaks = seq(20,70, by= 5)) +
  # Neu: manuelle Spezifikation der Farben
  scale_fill_manual(
    values = c(tuerkis, gruen, rot, gelb),
    breaks = c("africa", "americas", "asia", "europe")) +
  # Neu: Theme (Anpassung der Schriftgroesse, relativ zur Groesse 12, blaues Raster im Hintergrund, Rand für die Legende)
  theme(text = element_text(size=12),
        axis.text = element_text(size=rel(.8)),
        axis.title = element_text(size=rel(1.2)),
        panel.grid.major = element_line(colour = "azure2")) +
  # Neu: Titel, Beschriftungen der Achse und Legende
  labs(title="Bubble Chart im Gapminder-Look",
       subtitle = "Jahr: {floor(frame_time)}",
       x="Gini-Index",
       y="Happiness Score (WHR)",
       fill="Weltregion",
       size="Einwohnerzahl\n(in Mio.)") +
  # Neu: Vergroessern der Punkte fuer die Farb-Legende fuer die Kontinente
  guides(fill = guide_legend(override.aes = list(size = 5), order=1)) 

p_static + transition_time(time) +
  ease_aes("linear")

Animierte Grafiken speichern

Die mit gganimate animierten Grafiken können mit der Funktion anim_save() als gif-Datei gespeichert werden.

p_anim <- p_static + transition_time(time) +
  ease_aes("linear") 

anim_save("bubbles.gif", animation = p_anim)

Um die Größe und Proportionen der gespeicherten Animation zu kontrollieren, kann man wie folgt vorgehen:

animate(p_anim, height = 10, width = 20, units = "cm", res = 150)
anim_save("bubbles_wide.gif")

Interaktive Grafiken

Mit dem Paket plotly lassen sich interaktive Grafiken erzeugen:

  • einzelne Fälle bzw. Gruppen von Fällen können hevorgehoben werden
  • es kann in Plots hereingezoomt werden
  • per mouse-over werden Textfelder zum jeweiligen Datenpunkt angezeigt, deren Inhalt und Aufbau sich genau definieren lässt

Interaktive Grafik mit plotly

Auch hier bildet eine statische, mit ggplot erzeugte Grafik den Ausgangspunkt.

gapminder <- readRDS(here::here("data", "gapminder_dat.rds"))

options(scipen=10)
# Farben der vier Weltregionen 
tuerkis <- rgb(0,213,233, max=255)
gruen <- rgb(127,235,0, max=255)
rot <- rgb(255,88,114, max=255)
gelb <- rgb(255,231,0, max=255)

p_bubble <- gapminder %>%
  # Auswahl der Daten von 2023:
  subset(time == 2023) %>% 
    # Neu: Angabe der Einwohnerzahl in Millionen
  mutate(pop = pop/1000000) %>%
  # Grund-Grafik anfordern:
  ggplot(aes(x=gini, y=hapiscore_whr)) +
  # Neu: Text für die Jahreszahl ("2015") einfügen, sodass diese ganz im Hintergrund steht
  annotate("text", x=45, y=50, label="2023", size=85, colour ="grey90", family="mono", fontface=1) +
  # Neu: Farbthema: heller Hintergrund, schwarze Linien an x- und y-Achse
  theme_classic() + 
  # Wie bisher: Punkte einzeichnen --> Streu-Punkt-Diagramm,
  # Neu: Unterscheidung der Punkte nach Farbe (Region) und Größe (Population);  
  # Transparenz der Datenpunkte (alpha), Rand um die Punkte (shape) 
  geom_point(aes(fill = world_4region, size = pop), shape=21, alpha=.7) +
  # Skalieren der Größe der Punkte, sodass die Unterschiede deutlicher sind
  scale_size(range = c(1, 30)) +
  # Neu: Beschriftung der Achsen
  labs(x="Gini-Index", y="Hyppiness Score") +
  # Neu: manuelle Spezifikation der y-Achse: Wertebereich, Position der Beschriftungen (10er-Schritte)
  scale_y_continuous(limits = c(15, 85), 
                     breaks = seq(20,80, by=10),
                     labels = paste0(seq(20,80, by=10), "%")) +
  # Neu: manuelle Spezifikation der x-Achse: Wertebereich, log-Transformation, Position und Name der Beschriftungen
  scale_x_continuous(limits = c(18,75),
                     breaks = seq(20,70, by= 5)) +
  # Neu: manuelle Spezifikation der Farben
  scale_fill_manual(
    values = c(tuerkis, gruen, rot, gelb),
    breaks = c("africa", "americas", "asia", "europe")) +
  # Neu: Theme (Anpassung der Schriftgroesse, relativ zur Groesse 12, blaues Raster im Hintergrund, Rand für die Legende)
  theme(text = element_text(size=12),
        axis.text = element_text(size=rel(.8)),
        axis.title = element_text(size=rel(1.2)),
        panel.grid.major = element_line(colour = "azure2")) +
  # Neu: Titel, Beschriftungen der Achse und Legende
  labs(title="Bubble Chart im Gapminder-Look",
       subtitle="Jahr: 2023",
       x="Gini-Index",
       y="Happiness Score (WHR)",
       fill="Weltregion",
       size="Einwohnerzahl\n(in Mio.)") +
  # Neu: Vergroessern der Punkte fuer die Farb-Legende fuer die Kontinente
  guides(fill = guide_legend(override.aes = list(size = 5), order=1)) 

p_bubble

Interaktive Grafik mit plotly

Wendet man nun ggplotly() darauf an, entsteht diese interaktive Grafik. Das mouse-over-Textfeld funktioniert bereits, ließe sich aber auch noch feiner anpassen (Stichwort: tooltip).

ggplotly(p_bubble) 

Interaktive Grafiken speichern

Die mit ggplotly erzeugten HTML-Objekte können mit der Funktion saveWidget() aus dem R-Paket htmlwidgets als HTML-Datei gespeichert werden.

p_plotly <- ggplotly(p_bubble) 
saveWidget(p_plotly, file = "bubbles.html")

Um die Größe und Proportionen der HTML-Grafik zu kontrollieren, kann man wie folgt vorgehen:

p_plotly <- ggplotly(p_bubble) %>%
  layout(width = 1200, height = 400)

saveWidget(p_plotly, file = "bubbles_wide.html")

Abbildung von Allison Horst